package pl.edu.mimuw.irs.core.model.petrinet;

import java.util.HashSet;
import java.util.Set;

import pl.edu.mimuw.irs.core.exception.InternalException;
import pl.edu.mimuw.irs.core.exception.InternalException.Cause;
import pl.edu.mimuw.irs.core.global.IDManager;
import pl.edu.mimuw.irs.core.util.Position;

/**
 * @author Jakub Rauch
 * Created on: 2009-05-07
 */
public abstract class Node extends Element implements INode {

	private static final long serialVersionUID = -6271392860745827709L;
	
	// *** Attributes
	
	/** Name of this node. This is copied from {@link Element#getId()} when getter on null value is invoked. */
	private String name;
	/** Position of this node. */
	private Position position;
	/** Incoming arcs connected to this node. */
	private Set<Arc> incomingArcs;
	/** Outgoing arcs connected to this node. */
	private Set<Arc> outgoingArcs;
	 
	/* Getters and setters */
	@Override
	public String getName() {
		if (name == null) name = getId();
		return name;
	}
	@Override
	public void setName(String name) {
		if (this.name != name)
			getListeners().firePropertyChange("name", this.name, this.name = name);
	}
	@Override
	public Position getPosition() {
		if (position == null) position = new Position();
		return this.position;
	}
	/**
	 * @param position the position to set
	 */
	public void setPosition(Position position) {
		if (this.position != position) getListeners().firePropertyChange("position", this.position,	this.position = position);
	}
	public Set<Arc> getIncomingArcs() {
		if (incomingArcs == null) incomingArcs = new HashSet<Arc>();
		return incomingArcs;
	}
	public void setIncomingArcs(Set<Arc> incomingArcs) {
		this.incomingArcs = incomingArcs;
	}
	public Set<Arc> getOutgoingArcs() {
		if (outgoingArcs == null) outgoingArcs = new HashSet<Arc>();
		return outgoingArcs;
	}
	public void setOutgoingArcs(Set<Arc> outgoingArcs) {
		this.outgoingArcs = outgoingArcs;
	}
	
	// *** Constructors
	
	/** Serialization constructor */
	public Node() {}

	/**
	 * General constructor.
	 */
	public Node(IDManager idManager) {
		super(idManager);
	}
	
	/** Copying constructor */
	public Node(Node node) {
		super(node);
		this.name = node.getName();
		this.position = node.getPosition();
	}
	
	// *** Methods
	
	@Override
	public boolean isConnectedTo(INode node) {
		for (Arc arc : getOutgoingArcs()) {
			if (node.getIncomingArcs().contains(arc)) return true;
		}
		return false;
	}

	@Override
	public String toString() {
		return getName() + "(" + getId() + ")";
	}

	@Override
	public void addArc(Arc arc) {
		if (arc.getSource().equals(this)) {
			getOutgoingArcs().add(arc);
		} else if (arc.getTarget().equals(this)) {
			getIncomingArcs().add(arc);
		} else {
			throw new InternalException(Cause.PETRI_NET_NOT_CORRESPONDING_ARC, this, arc);
		}
	}
	
	@Override
	public void removeArc(Arc arc) {
		if (arc.getSource() == this) {
			getOutgoingArcs().remove(arc);
		} else if (arc.getTarget() == this) {
			getIncomingArcs().remove(arc);
		} else {
			throw new InternalException(Cause.PETRI_NET_NOT_CORRESPONDING_ARC, this, arc);
		}
	}
	
	public abstract Node clone();
}
